package com.coffee.admin.utils;

import com.alibaba.fastjson.JSONObject;
import com.coffee.core.util.MD5Util;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.math.BigDecimal;
import java.security.KeyStore;
import java.util.*;

@Component
public class WXPayUtil {
    private final static Logger LOG = LoggerFactory.getLogger(WXPayUtil.class);

    public static String zhengshu;

    public static String mchId;

    public static String appId;

    public static String newAppId;

    public static String signKey;

    @Value("${parameter.weixin.zhengshu}")
    private void setZhengshu(String appzhengshuStr) {
        zhengshu = appzhengshuStr;
    }

    @Value("${parameter.weixin.mchId}")
    private void setMchId(String mchIdStr) {
        mchId = mchIdStr;
    }

    @Value("${parameter.weixin.appId}")
    private void setAppId(String appIdStr) {
        appId = appIdStr;
    }

    @Value("${parameter.weixin.newAppId}")
    private void setNewAppId(String newAppIdStr) {
        newAppId = newAppIdStr;
    }

    @Value("${parameter.weixin.signKey}")
    private void setSignKeyStr(String signKeyStr) {
        signKey = signKeyStr;
    }

    /*
     * @Description:微信退款
     * @param transOrder
     * @param billNo
     * @Date: 2017-9-11 14:35
     * @return:
     */
    public static String wxPayRefundParameter(Integer appletType, String notifyUrl, String billNo, String totalFee, String refundFee, String refundNo) {
        StringBuffer xml = new StringBuffer();
        String data = null;
        try {
            String nonceStr = genNonceStr();
            xml.append("</xml>");
            SortedMap<String, String> parameters = new TreeMap<String, String>();
            if (appletType == 1) {
                parameters.put("appid", appId);
            } else {
                parameters.put("appid", newAppId);
            }
            parameters.put("mch_id", mchId);
            parameters.put("nonce_str", nonceStr);
            parameters.put("transaction_id", billNo);
            parameters.put("out_refund_no", refundNo);
            parameters.put("fee_type", "CNY");
            parameters.put("total_fee", totalFee);
            parameters.put("refund_fee", refundFee);
            parameters.put("op_user_id", mchId);
            parameters.put("notify_url", notifyUrl);
            parameters.put("sign", createSign(parameters, signKey));
            data = SortedMaptoXml(parameters);
            LOG.info("wxPayRefundParameter==========" + data);
        } catch (Exception e) {
            System.err.println(e.getMessage());
            return null;
        }
        return data;
    }


    public static JSONObject wxPayRefund(Integer appletType, String notifyUrl, String billNo, double totalFee, double refundFee, String refundNo) {
        try {
            LOG.info("zhengshu==" + zhengshu + ",mchId==" + mchId + ",appId===" + appId + ",signKey" + signKey);
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            FileInputStream instream = new FileInputStream(new File(zhengshu));
            try {
                keyStore.load(instream, mchId.toCharArray());
            } catch (Exception e) {
                LOG.error("加载证书异常：" + e);
                e.printStackTrace();
            } finally {
                instream.close();
            }
            // Trust own CA and all self-signed certs
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mchId.toCharArray()).build();
            // Allow TLSv1 protocol only
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslcontext, new String[]{"TLSv1"}, null,
                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom()
                    .setSSLSocketFactory(sslsf).build();

            HttpPost httppost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");
            //微信金额的单位是分 所以这里要X100 转成int是因为 退款的时候不能有小数点
            String totalFeeStr = new BigDecimal(totalFee + "").multiply(new BigDecimal(100)).intValue() + "";
            String refundFeeStr = new BigDecimal(refundFee + "").multiply(new BigDecimal(100)).intValue() + "";

            String xml = wxPayRefundParameter(appletType, notifyUrl, billNo, totalFeeStr, refundFeeStr, refundNo);
            try {
                StringEntity se = new StringEntity(xml);
                httppost.setEntity(se);
                LOG.info("executing request" + httppost.getRequestLine());
                CloseableHttpResponse responseEntry = httpclient.execute(httppost);
                try {
                    HttpEntity entity = responseEntry.getEntity();
                    LOG.info("statusLine==================" + responseEntry.getStatusLine());
                    if (entity != null) {
                        LOG.info("Response content length: " + entity.getContentLength());
                        LOG.info("=================content====================" + JSONObject.toJSONString(entity.getContent()));
                        SAXReader saxReader = new SAXReader();
                        Document document = saxReader.read(entity.getContent());
                        Element rootElt = document.getRootElement();
                        LOG.info("=================rootElt====================" + document.getRootElement());
                        String resultCode = rootElt.elementText("result_code");
                        LOG.info("=================resultCode====================" + resultCode);
                        JSONObject result = new JSONObject();
                        if (resultCode.equals("SUCCESS")) {
                            result.put("status", "success");
                            result.put("msg", "success");
                            result.put("refundId", rootElt.elementText("refund_id"));
                        } else {
                            result.put("status", "false");
                            result.put("msg", rootElt.elementText("err_code_des"));
                            LOG.info("=================msg====================" + JSONObject.toJSONString(rootElt.elementText("err_code_des")));
                        }
                        return result;
                    }
                    EntityUtils.consume(entity);
                } finally {
                    responseEntry.close();
                }
            } finally {
                httpclient.close();
            }
            return null;
        } catch (Exception e) {
            LOG.info(e.getMessage(), e);
            JSONObject result = new JSONObject();
            result.put("status", "false");
            result.put("msg", e.getMessage());
            return result;
        }
    }


    /**
     * @param params
     * @Description:请求值转换为xml格式 SortedMap转xml
     * @Date: 2017-9-7 17:18
     */
    private static String SortedMaptoXml(SortedMap<String, String> params) {
        StringBuilder sb = new StringBuilder();
        Set es = params.entrySet();
        Iterator it = es.iterator();
        sb.append("<xml>\n");
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            Object v = entry.getValue();
            sb.append("<" + k + ">");
            sb.append(v);
            sb.append("</" + k + ">\n");
        }
        sb.append("</xml>");
        return sb.toString();
    }

//    public static String createSign(String characterEncoding, SortedMap<Object, Object> parameters) {
//
//        StringBuffer sb = new StringBuffer();
//        Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序（升序）
//        Iterator it = es.iterator();
//        while (it.hasNext()) {
//            Map.Entry entry = (Map.Entry) it.next();
//            String k = (String) entry.getKey();
//            Object v = entry.getValue();
//            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
//                sb.append(k + "=" + v + "&");
//            }
//        }
//        sb.append("key=" + WXPayConstants.API_KEY);
//        String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
//        return sign;
//    }

    /**
     * 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
     */
    public static String createSign(SortedMap<String, String> packageParams, String AppKey) {
        StringBuffer sb = new StringBuffer();
        Set es = packageParams.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + AppKey);
        String sign = MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase();
        return sign;
    }

    public static String genNonceStr() {
        Random random = new Random();
        return MD5Util.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
    }
}
